<?php
namespace addons\stats;

use think\Addons;
use think\facade\Db;
use think\facade\Config;
use app\common\annotation\HooksAnotation;

class Plugin extends Addons
{
    // 该插件的基础信息
    public $info = [
        'name' => 'stats',
        'title' => '访问统计',
        'description' => '访问量概况、来源搜索引擎分析、统计搜索引擎来源数据、来访分析、访问明细',
        'status' => 1,
        'author' => 'HuoCMS',
        'require' => '1.0.0',
        'version' => '1.0.0',
        'website' => '',
        'images'=>'addons/stats/images/stats.jpg',
        'group'=>'',
        'is_hook'=>1,
        // 依赖插件
        'need_plugin' => [
            ['cms','1.0.0','>='],
        ],
        'tables' => [
            'visit_day',
            'visit_detail',
            'visit_summary',
        ],
    ];
    // 该插件后台菜单信息
    public $menu = [
        'is_nav' => 0,
        'menu' => [
            "title" => '访问统计',
            "title_en" => 'stats',
            'name'=>'admin/cms.Stats',
            'type'=>1,
            'condition'=>'',
            "status" => 1,
            'show'=>1,
            "icon" =>'laptop',
            'remark'=>'',
            "sort" => 18,
            'menulist' => [
                [
                    "title" => '访问量概况',
                    "title_en" => 'Overview of Visits',
                    'name'=>'admin/cms.Stats/statistics',
                    'type'=>1,
                    'condition'=>'',
                    "status" => 1,
                    'show'=>1,
                    "icon" =>'',
                    'remark'=>'',
                    "sort" => 3,
                    'menulist' => [
                        [
                            'name' => 'admin/cms.Stats/allstats', 
                            'title' => '全部访问量', 
                            'status' => 1,
                            'show' => 0,
                        ],
                    ]
                ],
                [
                    "title" => '搜索引擎',
                    "title_en" => 'Search Engines',
                    'name'=>'admin/cms.Stats/search_engine',
                    'type'=>1,
                    'condition'=>'',
                    "status" => 1,
                    'show'=>1,
                    "icon" =>'',
                    'remark'=>'',
                    "sort" => 2,
                ],
                [
                    "title" => '来访分析',
                    "title_en" => 'Visit Analysis',
                    'name'=>'admin/cms.Stats/source',
                    'type'=>1,
                    'condition'=>'',
                    "status" => 1,
                    'show'=>1,
                    "icon" =>'',
                    'remark'=>'',
                    "sort" => 1,
                    'menulist' => [
                        [
                            'name' => 'admin/cms.Stats/details', 
                            'title' => '访问明细', 
                            'status' => 1,
                            'show' => 0,
                        ],
                        [
                            'name' => 'admin/cms.Stats/ante_page', 
                            'title' => '来路分析', 
                            'status' => 1,
                            'show' => 0,
                        ],
                    ]
                ],
            ]
        ]
    ];
    /**
     * 插件安装方法
     * @return bool
     */
    public function install()
    {
        return true;
    }
    /**
     * 插件卸载方法
     * @return bool
     */
    public function uninstall()
    {
        return true;
    }
    /**
     * 插件使用方法
     * @return bool
     */
    public function enabled()
    {
        return true;
    }
    /**
     * 插件禁用方法
     * @return bool
     */
    public function disabled()
    {
        return true;
    }
    /**
     * @HooksAnotation(description="前台统计",type="2")
     * @return [type] [description]
     */
    public function Stats()
    {
        // 判断是否安装
        if(!isAddonInstall($this->name)){
            return false;
        }
        $config = getAddonConfig($this->name);
        // 是否开启统计
        if ($config['WEB_STATS_OPEN']) {
            // 来访也路径$_SERVER ['HTTP_REFERER']获取前一页面的 URL 地址
            $from_url = trim(isset($_SERVER ['HTTP_REFERER']) ? $_SERVER ['HTTP_REFERER'] : '');
            $vists_url = trim(get_url()); // 获取当前页面完整URL地址get_url()
            $browser = getbrowser();
            if (!empty ($_SERVER ['HTTP_CLIENT_IP'])) {
                $ip = $_SERVER ['HTTP_CLIENT_IP'];
            } elseif (!empty ($_SERVER ['HTTP_X_FORWARDED_FOR'])) {
                $ip = $_SERVER ['HTTP_X_FORWARDED_FOR'];
            } else {
                $ip = $_SERVER ['REMOTE_ADDR'];
            }
            if ($ip == '::1') {
                $ip = '127.0.0.1';
            }
            if ((checkadd(1, $ip) && checkadd(2, $vists_url) && $browser != '')) {
                $stime = strtotime(date("Y-m-d H:i:s"));
                $dtime = strtotime(date('Y-m-d'));
                $dstime = strtotime(date("Y-m-d 00:00:00"));
                $detime = strtotime(date("Y-m-d 23:59:59"));
                $uvcook = $this->is_setUVCookie();
                $is_pc = false;
                $is_mobile = false;
                if (is_mobile()) {
                    $is_mobile = true;
                } else {
                    $is_pc = true;
                }
                $map[] = ['stattime', '=', $dtime];
                $visit = Db::name('visit_summary')->where($map)->find();
                $set_stat_maxok = 1;
                // 每日访问最大值,为防止恶意攻击，超出后不再记录来访信息
                $set_stat_max = $config['WEB_STATS_MAX'];
                if ($visit) {
                    $dmap[] = [
                        ['ip', '=', $ip],
                        ['acctime', 'between', [$dstime, $detime]]
                    ];
                    $dvisit = Db::name('visit_day')->where($dmap)->find();
                    $pv = $visit ['pv'] + 1;
                    if ($pv < $set_stat_max) {
                        $sdata ['ip'] = $dvisit ? $visit ['ip'] : $visit ['ip'] + 1;
                        $sdata ['pv'] = $pv;
                        $sdata ['alone'] = $dvisit && $uvcook ? $visit ['alone'] : $visit ['alone'] + 1;
                        $sdata ['ismobile'] = $dvisit && !$is_mobile ? $visit ['ismobile'] : $visit ['ismobile'] + 1;
                        $sdata ['ispc'] = $dvisit && !$is_pc ? $visit ['ispc'] : $visit ['ispc'] + 1;
                        $parip = $dvisit ? 0 : 1;
                        $paral = $dvisit && $uvcook ? 0 : 1;
                        $sdata ['parttime'] = parttime(date('G'), $visit ['parttime'], 1, $parip, $paral);
                        $smap[] = ['id', '=', $visit ['id']];
                        Db::name('visit_summary')->where($smap)->update($sdata);
                    } else {
                        $set_stat_maxok = 0;
                    }
                } else {
                    $part = '';
                    for ($i = 0; $i < 24; $i++)
                        $part .= '|';
                    $parttime = parttime(date('G'), $part, 1, 1, 1);
                    $sdata ['pv'] = '1';
                    $sdata ['ip'] = '1';
                    $sdata ['alone'] = '1';
                    $sdata ['ismobile'] = $is_mobile ? '1' : '0';
                    $sdata ['ispc'] = $is_pc ? '1' : '0';
                    $sdata ['parttime'] = $parttime;
                    $sdata ['stattime'] = $dtime;
                    Db::name('visit_summary')->insert($sdata);
                }
                // 如果没有超过访问最大值
                if ($set_stat_maxok) {
                    $fromkey = keytype($from_url);
                    // $cate = get_cate_art($vists_url);
                    $cate = get_cate_art();
                    if (!$cate['city']) {
                        $cate['city'] = '';
                    }
                    if (!$cate['cateid']) {
                        $cate['cateid'] = 0;
                    }
                    $fromkey [0] = sqlinsert($fromkey [0]);
                    $fromkey [1] = sqlinsert($fromkey [1]);
                    /*
                     * $fromkeyk = ''; if (stristr ( $from_url, 'www.google' ) || stristr ( $from_url, 'yahoo.' )) { $fromkeyk = '无法获取'; $fromkey [0] = null; }
                     */
                    // 如果是关键词访问
                    // if (($fromkey && htmlspecialchars($fromkey [0]) != '') || $fromkeyk == '无法获取') {
                    if (($fromkey && htmlspecialchars($fromkey [0]) != '' || htmlspecialchars($fromkey [1]) != '')) {
                        $vimap[] = ['name', '=', $fromkey[0]];
                        $vimap[] = ['stattime', '=', $dtime];
                        $vimap[] = ['type', '=', 1];
                        // 查找当前关键词是否存在
                        $keyin = Db::name('visit_detail')->where($vimap)->find();
                        if ($keyin) {
                            // 取出浏览器id-点击数
                            $keyin_engine = explode('|', $keyin ['engine']);
                            $engine = '';
                            $p = 0;
                            for ($i = 0; $i < count($keyin_engine); $i++) {
                                if ($keyin_engine [$i] != '') {
                                    $rk = explode('-', $keyin_engine [$i]);
                                    // 如果浏览id 等于 当前浏览器ID
                                    if ($rk [0] == $fromkey [1]) {
                                        // 点击数加1
                                        $k = $rk [1] + 1;
                                        $keyin_engine [$i] = $rk [0] . '-' . $k;
                                        $p = 1;
                                    }
                                    // 拼接新的字符串
                                    $engine .= $keyin_engine [$i] . '|';
                                }
                            }
                            if ($p == 0) {
                                $engine = $engine . '|' . $fromkey [1] . '-1|';
                            }
                            $vmap[] = ['ip', '=', $ip];
                            $vmap[] = ['acctime', 'between', [$dstime, $detime]];
                            $vmap[] = ['antepage', '=', $from_url];
                            $visd = Db::name('visit_day')->where($vmap)->find();

                            $vdata ['pv'] = $keyin ['pv'] + 1;
                            $vdata ['ip'] = !$visd ? $keyin ['ip'] + 1 : $keyin ['ip'];
                            $vdata ['alone'] = $visd && $uvcook ? $keyin ['alone'] : $keyin ['alone'] + 1;
                            $vdata ['engine'] = $engine;
                            $vdata ['type'] = '1';
                            $vwre[] = ['id', '=', $keyin ['id']];
                            Db::name('visit_detail')->where($vwre)->update($vdata);
                        } else {
                            if ($fromkey [0] != '' || $fromkey [1] != '') {
                                $fromkey [1] = $fromkey [1] . '-1|';
                                $vdata ['name'] = $fromkey [0];
                                $vdata ['pv'] = '1';
                                $vdata ['ip'] = '1';
                                $vdata ['alone'] = '1';
                                $vdata ['remark'] = $cate ['city'];
                                $vdata ['engine'] = $fromkey [1];
                                $vdata ['type'] = '1';
                                $vdata ['cateid'] = $cate ['cateid'];
                                $vdata ['artid'] = $cate ['artid'];
                                $vdata ['stattime'] = $dtime;
                                Db::name('visit_detail')->insert($vdata);
                            }
                        }
                    }
                    // 如果关键词访问为空，并且有其他路径访问
                    if (empty ($fromkey [0]) && empty ($fromkey [1]) && !empty ($from_url)) {
                        $vimap[] = ['name', '=', $vists_url];
                        $vimap[] = ['stattime', '=', $dtime];
                        $vimap[] = ['type', '=', '2'];
                        // 查找当前数据是否存在
                        $urlin = Db::name('visit_detail')->where($vimap)->find();
                        if ($urlin) {
                            $vmap[] = ['ip', '=', $ip];
                            $vmap[] = ['acctime', 'between', [$dstime, $detime]];
                            $vmap[] = ['visitpage', '=', $vists_url];
                            $visd = Db::name('visit_day')->where($vmap)->find();
                            $vdata ['pv'] = $urlin ['pv'] + 1;
                            $vdata ['ip'] = !$visd ? $urlin ['ip'] + 1 : $urlin ['ip'];
                            $vdata ['alone'] = $visd && $uvcook ? $urlin ['alone'] : $urlin ['alone'] + 1;
                            $vdata ['engine'] = '';
                            $vdata ['type'] = '2';
                            $vwre ['id'] = $urlin ['id'];
                            Db::name('visit_detail')->where($vwre)->update($vdata);
                        } else {
                            $vdata ['name'] = $vists_url;
                            $vdata ['pv'] = '1';
                            $vdata ['ip'] = '1';
                            $vdata ['alone'] = '1';
                            $vdata ['engine'] = '';
                            $vdata ['type'] = '2';
                            $vdata ['remark'] = $cate ['city'];
                            $vdata ['cateid'] = $cate ['cateid'];
                            $vdata ['artid'] = $cate ['artid'];
                            $vdata ['stattime'] = $dtime;
                            Db::name('visit_detail')->insert($vdata);
                        }
                    }
                    // 如果来源路径为空，就是直接访问者
                    if (empty ($from_url)) {
                        $vimap[] = ['name', '=', $vists_url];
                        $vimap[] = ['stattime', '=', $dtime];
                        $vimap[] = ['type', '=', '3'];
                        // 查找当前情况数据是否存在
                        $furlin = Db::name('visit_detail')->where($vimap)->find();
                        if ($furlin) {
                            $vmap[] = ['ip', '=', $ip];
                            $vmap[] = ['acctime', 'between', [$dstime, $detime]];
                            $vmap[] = ['antepage', '=', $from_url];

                            $visd = Db::name('visit_day')->where($vmap)->find();

                            $vdata ['pv'] = $furlin ['pv'] + 1;
                            $vdata ['ip'] = !$visd ? $furlin ['ip'] + 1 : $furlin ['ip'];
                            $vdata ['alone'] = $visd && $uvcook ? $furlin ['alone'] : $furlin ['alone'] + 1;
                            $vdata ['engine'] = '';
                            $vdata ['type'] = '3';
                            $vwre[] = ['id', '=', $furlin ['id']];
                            Db::name('visit_detail')->where($vwre)->update($vdata);
                        } else {
                            $vdata ['name'] = $vists_url;
                            $vdata ['pv'] = '1';
                            $vdata ['ip'] = '1';
                            $vdata ['alone'] = '1';
                            $vdata ['engine'] = '';
                            $vdata ['type'] = '3';
                            $vdata ['remark'] = $cate ['city'];
                            $vdata ['cateid'] = $cate ['cateid'];
                            $vdata ['artid'] = $cate ['artid'];
                            $vdata ['stattime'] = $dtime;
                            Db::name('visit_detail')->insert($vdata);
                        }
                    }
                    $dymap ['ip'] = $ip;
                    $dymap ['acctime'] = $stime;
                    $dymap ['visitpage'] = $vists_url;
                    $dymap ['antepage'] = $from_url;
                    $dymap ['cateid'] = $cate ['cateid'];
                    $dymap ['artid'] = $cate ['artid'];
                    $dymap ['browser'] = $browser;
                    $dymap ['ismobile'] = $is_mobile ? '1' : '0';
                    $dymap ['address'] = ip_address($ip);
                    $dymap ['network'] = '';
                    $dymap ['lang'] = '';
                    Db::name('visit_day')->insert($dymap);
                    //
                }
            }
        }
    }
    /**
     * @HooksAnotation(description="后台清理统计",type="2")
     * @return [type] [description]
     */
    public function ClearStats()
    {
        // 判断是否安装
        if(!isAddonInstall($this->name)){
            return false;
        }
        $config = getAddonConfig($this->name);
        if ($config['WEB_STAT_CR1']) {
            $this->delet_estat_cr(1, $config['WEB_STAT_CR1']);
        }
        if ($config['WEB_STAT_CR2']) {
            $this->delet_estat_cr(2, $config['WEB_STAT_CR2']);
        }
        if ($config['WEB_STAT_CR3']) {
            $this->delet_estat_cr(3, $config['WEB_STAT_CR3']);
        }
        if ($config['WEB_STAT_CR4']) {
            $this->delet_estat_cr(4, $config['WEB_STAT_CR4']);
        }
        if ($config['WEB_STAT_CR5']) {
            $this->delet_estat_cr(5, $config['WEB_STAT_CR5']);
        }
    }
    /**
     * [is_setUVCookie 设置cookie]
     * @return boolean [description]
     */
    protected function is_setUVCookie()
    {
        if (!cookie('UVCOOKIE')) {
            // microtime ()函数是返回当前 Unix 时间戳的微秒数：
            // get_userip()获取当前用户ip
            // rand()随机数
            $value = md5(microtime() . get_userip() . rand());
            //mktime返回一个日期的 UNIX 时间戳，然后使用它来查找该日期的天：
            $overTime = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y')) - time();
            cookie('UVCOOKIE', $value, $overTime);
            return false;
        } else {
            return true;
        }
    }
    /**
     * [delet_estat_cr 程序每日会清空设置时间前的统计数据]
     * @param  [type] $type  [1：统计概况，2：搜索引擎，3：受访分析，4：来路分析，5：访问明细]
     * @param  [type] $value [0：从不清空，1：仅保留当天，2：保留近七天，3：保留近一个月，4：保留近一年]
     * @return [type]        [description]
     */
    protected function delet_estat_cr($type, $value)
    {
        $time = date('Y-m');
        $string = '';
        switch ($value) {
            case 1:
                //当天时间
                $st = strtotime(date("Y-m-d", time()));
                break;
            case 2:
                //七天时间
                $st = strtotime(date("Y-m-d", strtotime("-6 day")));
                break;
            case 3:
                //一个月时间
                $st = strtotime(date("Y-m-d", strtotime("-1 month")));
                break;
            case 4:
                //一年时间
                $st = strtotime(date('Y-m-d', strtotime("-1 Year")));
                break;
        }
        if ($st) {
            switch ($type) {
                case 1:
                    $Summary = Db::name('visit_summary');
                    $tableName = Config::get('database.connections.mysql.prefix') . 'visit_summary';
                    $map1[] = ['stattime', '<', $st];
                    $slist = $Summary->where($map1)->select();
                    foreach ($slist as $key => $val) {
                        $string .= "INSERT INTO {$tableName} VALUES('','$val[pv]','$val[ip]','$val[alone]','$val[ispc]','$val[ismobile]','$val[parttime]','$val[stattime]');\n";
                    }
                    $flag = $Summary->where($map1)->delete();
                    break;
                case 2:
                    $Detail = Db::name('visit_detail');
                    $tableName = Config::get('database.connections.mysql.prefix') . 'visit_detail';
                    $map2[] = ['stattime', '<', $st];
                    $map2[] = ['type', '=', '1'];
                    $slist = $Detail->where($map2)->select();
                    foreach ($slist as $key => $val) {
                        $string .= "INSERT INTO {$tableName} VALUES('','$val[name]','$val[pv]','$val[ip]','$val[alone]','$val[remark]','$val[type]','$val[cateid]','$val[artid]','$val[engine]','$val[ismobile]','$val[stattime]','$val[lang]');\n";
                    }
                    $flag = $Detail->where($map2)->delete();
                    break;
                case 3:
                    $Detail = Db::name('visit_detail');
                    $tableName = Config::get('database.connections.mysql.prefix') . 'visit_detail';
                    $map3[] = ['stattime', '<', $st];
                    $map3[] = ['type', '=', '2'];
                    $slist = $Detail->where($map3)->select();
                    foreach ($slist as $key => $val) {
                        $string .= "INSERT INTO {$tableName} VALUES('','$val[name]','$val[pv]','$val[ip]','$val[alone]','$val[remark]','$val[type]','$val[cateid]','$val[artid]','$val[engine]','$val[ismobile]','$val[stattime]','$val[lang]');\n";
                    }
                    $flag = $Detail->where($map3)->delete();
                    break;
                case 4:
                    $Detail = Db::name('visit_detail');
                    $tableName = Config::get('database.connections.mysql.prefix') . 'visit_detail';
                    $map4[] = ['stattime', '<', $st];
                    $map4[] = ['type', '=', '3'];
                    $slist = $Detail->where($map4)->select();
                    foreach ($slist as $key => $val) {
                        $string .= "INSERT INTO {$tableName} VALUES('','$val[name]','$val[pv]','$val[ip]','$val[alone]','$val[remark]','$val[type]','$val[cateid]','$val[artid]','$val[engine]','$val[ismobile]','$val[stattime]','$val[lang]');\n";
                    }
                    $flag = $Detail->where($map4)->delete();
                    break;
                case 5:
                    $sitday = Db::name('visit_day');
                    $tableName = Config::get('database.connections.mysql.prefix') . 'visit_day';
                    $map5[] = ['acctime', '<', $st];
                    $slist = $sitday->where($map5)->select();
                    foreach ($slist as $key => $val) {
                        $string .= "INSERT INTO {$tableName} VALUES('','$val[ip]','$val[acctime]','$val[visitpage]','$val[antepage]','$val[cateid]','$val[artid]','$val[browser]','$val[address]','$val[network]','$val[ismobile]','$val[lang]');\n";
                    }
                    $flag = $sitday->where($map5)->delete();
                    break;
            }
            // $filepath = realpath(sys_config('DATA_BACKUP_PATH'));
            $filepath = PROJECT_PATH . sys_config('DATA_BACKUP_PATH');
            if (!file_exists($filepath . "/stat/")) mkdir($filepath . "/stat/", 0777, true);
            if ($string) file_put_contents($filepath . "/stat/$time.sql", $string, FILE_APPEND);
        }
    }
}
